﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;

namespace RaptorEngine.Managers
{
	public class AudioManager
	{
        #region Fields

        private Dictionary<String, SoundEffect> soundEffects;
        private SoundEffectInstance sei;

        private Dictionary<String, Song> _songs;
        private bool songRunning = false;
        public bool StartSong { set { songRunning = !value; } }
        private bool songPaused = false;
        public bool SongPaused { get { return songPaused;} }

        AudioEmitter emitter = new AudioEmitter();
        AudioListener listener = new AudioListener(); //eftersom vi alltid har en statisk, gemensam kamera så är listener statisk.

        public Vector3 ListenerPosition { get { return listener.Position; } set { listener.Position = value; } }

        private float globalVolume = 1.0f;

        #endregion
        #region Properties

        /// <summary>
        /// Gets or sets the global volume.
        /// </summary>
        /// <value>
        /// The global volume.
        /// </value>
        public float GlobalVolume
        {
            get { return globalVolume; }
            set { globalVolume = value; }
        }

        #endregion

        public AudioManager()
        {
            soundEffects = new Dictionary<string, SoundEffect>();
            _songs = new Dictionary<string, Song>();
        }

        /// <summary>
        /// Plays the sound.
        /// </summary>
        /// <param name="sound">The sound.</param>
        /// <param name="volume">The volume.</param>
        public void PlaySound(string sound, float volume)
        {
            SoundEffect soundE;
            soundEffects.TryGetValue(sound, out soundE);
            
            if (soundE == null)
                return;

            soundE.Play(volume * globalVolume, 0.0f, 0.0f);
        }

        /// <summary>
        ///  Plays sound based on position to listener
        /// </summary>
        /// <param name="sound">The sound name</param>
        /// <param name="volume">Volume level. 0 - 1</param>
        /// <param name="position">The position of the sound emitter.</param>
        public void Play3DSound(string sound, float volume, Vector3 position)
        {
            SoundEffect soundE;
            soundEffects.TryGetValue(sound, out soundE);

            if (soundE == null)
                return;

            SoundEffect.MasterVolume = 1f;
            SoundEffect.DistanceScale = 20f;
            SoundEffect.DopplerScale = 20f;
            sei = soundE.CreateInstance();
            sei.IsLooped = false;
            sei.Pitch = 1.0f;
            sei.Volume = SoundEffect.MasterVolume * volume;

            emitter.Position = position;
            sei.Apply3D(listener, emitter);

            sei.Play();
        }


        /// <summary>
        /// Stops the looped sound.
        /// </summary>
        /// <param name="sound">The sound.</param>
        public void StopLoopedSound(string sound)
        {
            sei.Stop();
        }


        /// <summary>
        /// Plays the looped sound.
        /// </summary>
        /// <param name="sound">The sound.</param>
        /// <param name="volume">The volume.</param>
        public void PlayLoopedSound(string sound, float volume)
        {
            SoundEffect soundE;
            soundEffects.TryGetValue(sound, out soundE);

            if (soundE == null)
                return;

            sei = soundE.CreateInstance();
            sei.IsLooped = true;
            sei.Pitch = 1.0f;
            sei.Volume = globalVolume * volume;
            sei.Play();
        }

        /// <summary>
        /// Adds the sound effect.
        /// </summary>
        /// <param name="sound">The sound.</param>
        /// <param name="name">The name.</param>
        public void AddSoundEffect(SoundEffect sound, string name)
        {
            try
            {
                soundEffects.Add(name, sound);
            }
            catch (ArgumentException)
            {
            }
        }

        /// <summary>
        /// Gets the sound effect.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public SoundEffect GetSoundEffect(string name)
        {
            SoundEffect soundE;
            soundEffects.TryGetValue(name, out soundE);

            return soundE;
        }

        /// <summary>
        /// Method for adding a song to the song dictionary
        /// </summary>
        /// <param name="key"></param>
        /// <param name="song"></param>
        public void AddSong(string key, string song)
        {
            if (!_songs.ContainsKey(key))
            {
                _songs.Add(key, GameEngine.Instance.Load<Song>(song));
                MediaPlayer.IsRepeating = true;
                MediaPlayer.Volume = .2f;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="song"></param>
        public void PlayMusic(string song, bool repeat)
        {
            if (!songRunning)
            {
                if(_songs.ContainsKey(song))
                {
                    MediaPlayer.Play(_songs[song]);
                    MediaPlayer.IsRepeating = repeat;

                    songRunning = true;
                }
            }
        }

        /// <summary>
        /// Method for pausing music
        /// </summary>
        public void PauseMusic()
        {
            MediaPlayer.Pause();
            songPaused = true;
            
        }

        /// <summary>
        /// Method for resuming paused music.
        /// </summary>
        public void ResumeMusic()
        {
            MediaPlayer.Resume();
            songPaused = false;
        }

        /// <summary>
        /// Method for stopping playing music.
        /// </summary>
        public void StopMusic()
        {
            if (songRunning)
            {
                MediaPlayer.Stop();
                songRunning = !songRunning;
            }
        }
    }
}
